﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed
#pragma once

#include "GcmpModelInterface.h"
#include "IObject.h"
#include "RegenDataId.h"

namespace gcmp 
{
    class ElementId;
    class IDocument;
    class IBatchDataChangeRequest;

    /// \brief 文档更新器接口
    ///
    /// 文档更新器用来更新文档需要更新的数据，每个文档有且只有一个文档更新器
    FINAL_INTERFACE class GCMP_MODEL_INTERFACE_EXPORT IRegenerator : public IObject
    {
        DEFINE_CAST_DERIVED(gcmp::IRegenerator, gcmp::IObject);
    public:
        /// \brief 析构函数
        virtual ~IRegenerator() {}

        /// \brief 更新整个文档
        /// 
        /// 更新完成之后，整个文档的数据都处于最新状态
        /// \return 成功返回true，失败返回false
        virtual bool RegenerateDocument() = 0;

        /// \brief 更新当前Element
        /// 
        /// 更新完成后，此Element的数据都处于最新状态
        /// \param elementId 需要更新的Element的Id
        /// \return 成功返回true，失败返回false
        virtual bool RegenerateElement(const ElementId& elementId) = 0;

        /// \brief 强制更新Elements
        /// 
        /// 强制更新Element，即重新执行Element的所有计算器，无论它们依赖的数据是否更新
        /// \param elementIds 需要强制更新的Element的Ids
        /// \return 成功返回true，失败返回false
        virtual bool ForceRegeneratingElements(const std::vector<ElementId>& elementIds) = 0;

        /// \brief 强制更新Elements, 并Mark该Elements中所有计算器的输出数据
        /// 
        /// 强制更新Elements，即重新执行Element的所有计算器，无论它们依赖的数据是否更新
        /// \param elementIds 需要强制更新的Element的Ids
        /// \return 成功返回true，失败返回false
        virtual bool ForceRegeneratingElementsAndPropagate(const std::vector<ElementId>& elementIds) = 0;

        /// \brief 计算单个数据
        /// 
        /// 更新完成后，这个数据以及它依赖的数据处于最新状态
        /// \param dataId 需要更新的数据的Id
        /// \return 成功返回true，失败返回false
        virtual bool RegenerateData(const RegenDataId& dataId) = 0;

        /// \brief 标记数据发生了变化
        /// 
        /// 数据发生变化需要MarkRegenDataId以触发关联计算
        /// \param elementId 数据所属的Element的Id
        /// \param dataId 发生变化的数据的Id
        /// \return void
        virtual void MarkRegenDataId(const RegenDataId& dataId) = 0;

        /// \brief 取消标记数据发生变化
        /// \param dataId 取消发生变化的数据的Id
        /// \return void
        virtual void UnmarkRegenDataId(const RegenDataId& dataId) = 0;

        /// 移除Element所有已标记的数据。
        /// \param elementId 需要移除更新标记的Element的Id。
        /// \return void
        virtual void RemoveRegenElement(const ElementId& elementId) = 0;

        /// \brief 批量修改数据
        /// \param pBatchDataChangeRequestor 批量更改数据请求者，请求者中实现批量修改数据的逻辑
        /// \see IBatchDataChangeRequest
        /// \return 成功返回true，失败返回false
        virtual bool BatchDataChange(IBatchDataChangeRequest* pBatchDataChangeRequestor) = 0;

        /// \brief 验证关联更新数据使用是否合理
        /// 
        /// 用户在使用Get方法获取关联更新数据时，需调用此方法检测关联更新数据使用是否合法。若Get的数据是使用DATA_xx_REGEN宏定义的，
        /// 无需用户手动调用，框架中会做检测。
        /// \param elementId 数据所属的Element的Id
        /// \param dataId 数据对应的RegenDataId
        /// \return true：使用合理；false：使用不合理
        virtual bool ValidateRegenDataUse(const RegenDataId& dataId, std::wstring* errorMessage = nullptr) const = 0;

        /// \brief 是否正在执行关联更新
        /// \return true：是；false：否
        virtual bool IsRegerating() const = 0;
    };


    /// \brief 批量更改数据请求者接口
    ///
    /// 作为IRegenerator::BatchDataChange(IBatchDataChangeRequest*)接口的参数
    class GCMP_MODEL_INTERFACE_EXPORT IBatchDataChangeRequest : public IObject
    {
    public:
        /// \brief 析构函数
        virtual ~IBatchDataChangeRequest() {}

        /// \brief 请求批量修改数据
        /// 
        /// 用户重写此方法，并在此方法中实现批量修改数据的逻辑。此方法由框架调用，不允许用户自己调用。
        /// \return 成功返回true，失败返回false
        virtual bool Execute() = 0;
    };
}// namespace gcmp



